package com.dubbo.zk;

import com.dubbo.utils.ExceptionUtils;
import com.dubbo.utils.ThreadUtils;
import com.google.common.collect.Lists;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * @author Zhuyanfeng on 2018/3/21
 */
@Component
public class ZkClient {


    private static final Logger LOOGER = LoggerFactory.getLogger(ZkClient.class);

    @Value("${zkConn}")
    private String connectionInfo;
    private CuratorFramework curatorFramework;
    private ScheduledExecutorService executorService;
    private List<PathChildrenCache> pathChildrenCacheList = Lists.newArrayList();


    @PostConstruct
    public void start(){
        curatorFramework = CuratorFrameworkFactory.builder()
                .connectString(connectionInfo)
                .sessionTimeoutMs(5000)
                .connectionTimeoutMs(5000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .namespace("base") .build();
        curatorFramework.start();

        executorService = Executors.newScheduledThreadPool(2);
    }


    public void create(String path, CreateMode createMode, boolean ignoreExisted) {

        try {
            curatorFramework.create()
                    .creatingParentsIfNeeded()
                    .withMode(createMode)
                    .forPath(path);
        } catch (Exception e) {
            boolean ignore = ignoreExisted && (e instanceof KeeperException.NodeExistsException);
            if (!ignore) {
                ExceptionUtils.reThrowRuntimeException(e);
            }
        }
    }


    public void delete(String path) {
        try {
            curatorFramework.delete()
                    .deletingChildrenIfNeeded()
                    .forPath(path);
        } catch (Exception e) {
            ExceptionUtils.reThrowRuntimeException(e);
        }
    }

    public List<String> get(String path) {

        try {
            return curatorFramework.getChildren().forPath(path);
        } catch (KeeperException.NoNodeException e) {
            return Lists.newArrayList();
        } catch (Exception e) {
            throw ExceptionUtils.propagateAsUncheck(e);
        }

    }


    @PreDestroy
    public void stop() throws IOException {
            if (curatorFramework != null) {
                curatorFramework.close();
            }

            for (PathChildrenCache cache : pathChildrenCacheList)
            {
                cache.close();
            }
        ThreadUtils.stopScheduledExecutorService(executorService, "");
    }
}
